package com.way.flow.download

import com.way.flow.activity.DownloadInfo
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.catch
import kotlinx.coroutines.flow.flow
import kotlinx.coroutines.flow.flowOn
import okhttp3.OkHttpClient
import okhttp3.Request
import java.io.File
import java.io.IOException
import java.io.InputStream
import java.io.OutputStream

/**
 *  create by wang wei 2024/11/26
 *  email: Way_540927094@163.com
 *  describe:
 */
object DownloadManager {
    fun download(url: String, file: File): Flow<DownloadInfo> {
        return flow {
            val request = Request.Builder().get().url(url).build()
            val response = OkHttpClient.Builder().build().newCall(request).execute()
            if (response.isSuccessful){
                response.body()!!.let { body ->
                    val total = body.contentLength()
                    file.outputStream().use { output ->
                        val input = body.byteStream()
                        var emittedProgress = 0L
                        input.copyTo(output){ copied ->
                            val p = copied * 100 / total
                            if (p - emittedProgress > 5){
                                kotlinx.coroutines.delay(100)
                                emit(DownloadInfo.ProgressInfo(p.toInt()))
                                emittedProgress = p
                            }
                        }
                    }
                }
                emit(DownloadInfo.Done(file))

            }else{
                throw  IOException(response.toString())
            }
        }.catch {
            file.delete()
            emit(DownloadInfo.Error(it))
        }.flowOn(Dispatchers.IO)
    }
}

inline fun InputStream.copyTo(out: OutputStream, bufferSize: Int = DEFAULT_BUFFER_SIZE, process: (Int) -> Unit): Long {
    var bytesCopied: Long = 0
    val buffer = ByteArray(bufferSize)
    var bytes = read(buffer)
    while (bytes >= 0) {
        out.write(buffer, 0, bytes)
        bytesCopied += bytes
        bytes = read(buffer)
        process(bufferSize)
    }
    return bytesCopied
}